依賴反轉原則(Dependency Inversion Principle,DIP)
主要分為兩個重點
1、高階模組不應該依賴於低階模組,兩者都該依賴抽象。
2、抽象不應該依賴於具體實作方式,具體實作方式應該依賴抽象。
筆者這邊舉個現實的例子:
我是一個害羞內向的人
那麼替換掉具體實現,
我是一個伶牙俐齒的人。
這時候就有可能有問題,
這就是依賴於具體實現的問題,
在這邊就是我(高層)依賴了性格(底層)了具體實現。
而這時候就可以把高層抽象化,例如把我替換為抽象的筆者
筆者是一個害羞內向的人
筆者是一個伶牙俐齒的人
筆者是一個活潑好動的人
這時候就會是底層有了依賴反轉,
而由於現在筆者是一個抽象的,
那麼就會需要一個具體實現有描述筆者是誰。
我是筆者,而筆者是一個害羞內向的人
妳是筆者,而筆者是一個伶牙俐齒的人
他是筆者,而筆者是一個活潑好動的人
在這邊就是你我他(具體高層)依賴了筆者(抽象),
而性格(底層)也同樣依賴了筆者(抽象),
就這是依賴反轉。
而程式碼中有著許多反過來說,
那麼為什麼不底層次依賴於抽象呢?
因為會難以知道是什麼,
彈性跟測試還有其他都會難以去判斷。
一樣是剛剛的例子,
我是一個害羞內向的人,
這邊把底層抽象。
我是一個性格的人。
你是一個性格的人。
他是一個性格的人。
可以很明確地發現,
這樣的彈性就大幅降低,而且很難判斷到底實現了什麼。
所以DIP的做法其實是一種將低層模組的控制權從原來的高層模組中抽離,將兩者的耦合只放在抽象層上。
需要的物件(object),不用自己取得,而是服務(Server)提供給你。
那麼關於DIP主要達成的手法,筆者在這邊透過程式來介紹IOC與DI
控制反轉(IOC,Inversion of Control)
一種程式設計思想,也是DIP的一種實現方式。
IOC意味著將程式控制流程的主動權交給第三方(如框架或容器),而不是由程式員自己控制。這樣可以降低程式各個模組之間的依賴關係,提高程式的靈活性和可重用性。IOC通常通過DI或DL來實現。
依賴注入(DI,Dependency Injection)
是一種實現IOC的設計模式,它把被依賴的物件通過建構器、屬性或者方法參數的方式傳遞給被依賴的物件,從而實現IOC。
依賴查找(DL,Dependency Lookup)
是一種實現IOC的方法,它是指將依賴的物件存儲在一個容器中,被依賴的物件可以通過名稱或者類型來從容器中獲取所需的物件,從而實現控制反轉。
那麼看向程式,
依筆者所寫,可以看到 依賴注入 (Dependency Injection),
在 SupplierServiceBuilder 類別中的 GetServices 方法中。
這個方法通過抽象的介面 ICarInfomationService 來返回具體的供應商服務實例。
這種方式將依賴關係的創建工作從客戶端轉移到了 SupplierServiceBuilder,實現了控制反轉。
public class SupplierServiceBuilder
{
#region -Enum-
public enum EnumSupplierCode
{
[Description("")]
NoData,
[Description("富豪")]
VOLVO,
[Description("美國汽車")]
AMC,
[Description("特斯拉")]
Tesla,
}
#endregion
#region -Properties-
// 定義一個ICarInfomationService類型的屬性
private ICarInfomationService carInfomationService;
#endregion
#region -建構子-
// 在建構器中接收一個ICarInfomationService類型的物件
public SupplierServiceBuilder(ICarInfomationService carInfomationService)
{
// 將物件賦值給屬性
this.carInfomationService = carInfomationService;
}
#endregion
#region -Methods-
#region public
public ICarInfomationService GetCarInfomationService()
{
// 直接返回屬性
return carInfomationService;
}
#endregion
#region private
/// <summary>
/// 取得供應商服務
/// </summary>
/// <param name="pLocal"></param>
/// <returns></returns>
private CarInfomationService GetServices(string pLocal)
{
CarInfomationService lHotelService = null;
EnumSupplierCode enumReturn = new EnumSupplierCode();
//字串比對Enum的Description,找到對應的枚舉
foreach (var item in Enum.GetValues(typeof(EnumSupplierCode)))
{
if (GetDescription(item) == pLocal.ToUpper())
{
enumReturn = (EnumSupplierCode)item;
break;
}
}
switch (enumReturn)
{
case EnumSupplierCode.VOLVO:
lHotelService = new VOLVOService();
break;
case EnumSupplierCode.AMC:
lHotelService = new AMCService();
break;
case EnumSupplierCode.Tesla:
lHotelService = new TeslaService();
break;
}
return lHotelService;
}
private string GetDescription(object T)
{
var type = T.GetType();
var members = type.GetMember(T.ToString());
var attributes = members[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
return description;
}
#endregion
#endregion
}
筆者到此告一段落,如果要再深入探討IOC、DI、DL與其優缺點,又會需要一段不短的時間,
各位如果有興趣可以去嘗試看看DL要怎麼做,與寫寫看各種範例。
而在完整的看完SOLID,可以發現有很多相輔相成,
在實際製作中通常會根據不同需求來分配側重點,
在其中兩到三個會更重於其他。